package cc.wanforme.st.server.config.db.dynamic;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;

import cc.wanforme.st.server.util.PathResource;


/**数据库库配置用的是这个，单数据源<br>
 * @author wanne
 * 2020年4月26日
 * 
 */
@ConditionalOnProperty(prefix = "spring.datasource",name = "enable-dynamic",havingValue = "true")
@Configuration
public class DynamicDatabaseConfiguration {
	//private static final Logger log = LoggerFactory.getLogger(DynamicDatabaseConfiguration.class);
	
	/** 如果要这样注入，该路径只能填一个*/
	@Value("${mybatis-plus.mapper-locations}")
	private String mapper_locations;
	
	@Value("${mybatis-plus.type-aliases-package}")
	private String type_aliases_package;
	
	@Value("${mybatis-plus.configuration.map-underscore-to-camel-case}")
	private boolean configuration_map_underscore_to_camel_case;
	
	@Value("${mybatis-plus.configuration.log-impl}")
	private String configuration_log_impl;

	@Value("${spring.datasource.druid.sqlite.url}")
	private String sqliteUrl;
	
	@Value("${spring.datasource.druid.sqlite.emptyFile}")
	private String sqliteFile;
	
	@Bean(name = "default")
	@ConfigurationProperties("spring.datasource.druid.default")
	public DataSource defaultDatasource() {
		return DruidDataSourceBuilder.create().build();
	}
	
    @Bean(name = "sqlite")
    @ConfigurationProperties("spring.datasource.druid.sqlite")
    public DataSource sqlLite() throws IOException {
    	this.checkSqliteAndInit();
        DruidDataSource ds = DruidDataSourceBuilder.create().build();
        return ds;
    }
    
	// 预检查sqlite文件是否存在，不使用内置的数据库文件，复制一个新的出来
	private File checkSqliteAndInit() throws IOException {
		String file = null;
		if(sqliteUrl.startsWith("jdbc:sqlite::resource:")) {
			file = sqliteUrl.substring("jdbc:sqlite::resource:".length());
		} else {
			file = sqliteUrl.substring("jdbc:sqlite:".length());
		}
		
		// 可以自定义原始文件
		boolean fileExisted = PathResource.isFileExisted(file);
		if(!fileExisted) {
			PathResource.saveClassPathResource(sqliteFile, file);
		}
		return (new File(file)).getAbsoluteFile();
	}
	
	@Primary
	@Bean(name = "multiDataSource")
//	public DataSourceTransactionManager transactionManager(
	public DataSource multipleDataSource(
			@Qualifier("default") DataSource defaulDs, @Qualifier("sqlite") DataSource sqlisteDs) {
		DynamicRoutingDatasource datasource = new DynamicRoutingDatasource();
		Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(TableDbEnum.DEFAULT.getCode(), defaulDs);
        targetDataSources.put(TableDbEnum.SQLITE.getCode(), sqlisteDs);
        datasource.setTargetDataSources(targetDataSources);
		
		datasource.setDefaultTargetDataSource(defaulDs);
		return datasource;
	}
	
	// 没有持久层 就不要使用
	@SuppressWarnings("unchecked")
	@Primary
	@Bean(name = "sqlSessionFactory")
	public SqlSessionFactory sqlSessionFactory(@Qualifier("multiDataSource") DataSource multiDataSource) throws Exception {
		MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
		sqlSessionFactory.setDataSource(multiDataSource); 
		// sqlSessionFactory.setDataSource(multipleDataSource(defaultDatasource(), sqlLite()));
		
		// fix: 打包后, mybatis 无法识别 alias
		// 一种解决方式: https://blog.csdn.net/u012954706/article/details/103977335
		// 详细问题: https://blog.csdn.net/taotoxht/article/details/70171542
		sqlSessionFactory.setVfs(com.baomidou.mybatisplus.autoconfigure.SpringBootVFS.class); // mybatis-plus
		//sqlSessionFactory.setVfs(org.mybatis.spring.boot.autoconfigure.SpringBootVFS.class);  // mybatis
		// 如果上面的方式没有效果，那么请使用下面的代码
		VFS.USER_IMPLEMENTATIONS.add(com.baomidou.mybatisplus.autoconfigure.SpringBootVFS.class); // mybatis-plus
		// VFS.USER_IMPLEMENTATIONS.add(org.mybatis.spring.boot.autoconfigure.SpringBootVFS.class); // mybatis
		
		MybatisConfiguration configuration = new MybatisConfiguration();
		configuration.setJdbcTypeForNull(JdbcType.NULL);
		configuration.setMapUnderscoreToCamelCase(configuration_map_underscore_to_camel_case);
		configuration.setCacheEnabled(false);
		configuration.setLogImpl((Class<? extends Log>) Class.forName(configuration_log_impl));
		
		if(type_aliases_package != null) {
			String[] split = type_aliases_package.split("\\,");
			Arrays.asList(split).forEach( e-> {
				configuration.getTypeAliasRegistry().registerAliases(e.trim());
			});
		}
		sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapper_locations));
		sqlSessionFactory.setConfiguration(configuration);
		
	    return sqlSessionFactory.getObject();
	}
	
	
}
